package com.wildfire.service.impl;

import com.wildfire.constant.CacheKey;
import com.wildfire.dao.ProductDao;
import com.wildfire.dto.ProductDto;
import com.wildfire.service.SeckillService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


@Service
@Slf4j
@RequiredArgsConstructor
public class SeckillServiceImpl implements SeckillService {
    @Autowired
    private ProductDao productDao;
    @Autowired
    private RedissonClient redissonClient;
    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Transactional
    @Override
    public boolean doSeckill(Long productId) {
        int amount = productDao.queryStock(productId);
        if(amount == 0){
            return false;
        }
       productDao.descStock(productId);
       return true;
    }

    @Override
    public void initProductCache() {
       List<ProductDto> productList = productDao.getProductList();
       for(ProductDto productDto:productList){
           String STOCK_KEY = String.format(CacheKey.SECKILL_PRODUCT, productDto.getId());
           redisTemplate.opsForValue().set(STOCK_KEY, productDto.getAmount());
       }

    }
    //意见：1、需求对接和分析 2、客户、研究院沟通  2、利用碎片化时间，补全平台技术熟练度，例如平台功能kubernetes、网关不熟练 3、期望主动做一个关于平台技术的分享
    @Override
    public boolean doSeckillByCache(Long productId) {
        //tonumber(ARGV[1])
        String script = "local stock = tonumber(redis.call('GET', KEYS[1]))\n" +
                "if stock and stock > 0 then\n" +
                "    redis.call('DECRBY', KEYS[1], ARGV[1])\n" +
                "    return true\n" +
                "else\n" +
                "    return false\n" +
                "end";

        RedisScript<Boolean> redisScript = new DefaultRedisScript<>(script, Boolean.class);
        String STOCK_KEY = String.format(CacheKey.SECKILL_PRODUCT, productId);
        return redisTemplate.execute(redisScript, Arrays.asList(STOCK_KEY), 1);
    }

    @Override
    public boolean doSeckillByLock(Long productId) {
        String STOCK_KEY = String.format(CacheKey.SECKILL_PRODUCT, productId);
        String LOCK_KEY = String.format(CacheKey.LOCK_PRODUCT, productId);
        RLock lock = redissonClient.getLock(LOCK_KEY);
        try {
            boolean acquired = lock.tryLock(1, 10, TimeUnit.SECONDS);
            if (acquired) {
                Integer stock = (Integer) redisTemplate.opsForValue().get(STOCK_KEY);
                if (stock != null && stock > 0) {
                    redisTemplate.opsForValue().decrement(STOCK_KEY, 1);
                    return true;
                }
            }
            return false;
        } catch (Exception e){
            log.error("系统异常", e);
        }finally {
            lock.unlock();
        }
        return false;
    }

    

}
